﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;

public class PixelSplit
{
    List<PixelSplit> _child = new List<PixelSplit>();
    
    public int _size;
    public Sphere _sphere = new Sphere();
    private int _maxSplitRadius = 20;
    private List<Sphere> lstAdjacentSect = new List<Sphere>();
    public float _imgWidth = 1280.0f;
    public float _imgHeight = 720.0f;

    public void Create( int size )
    {
        _size = size;
        _sphere.center = new Vector3(0, 0, 0);
        _sphere.radius = (float)(size / 2);

        RecursiveSplit();

         StreamWriter sr = File.CreateText("test.txt");
         int dt = 0;
         WriteTest(ref sr, this, dt);
        
        sr.Close();

    }

    public void SetImageSize(float width, float height)
    {
        _imgWidth = width;
        _imgHeight = height;
    }

    void WriteTest(ref StreamWriter sr, PixelSplit pixelSplit, int depth)
    {
        if (pixelSplit._child.Count <= 0)
            return;

        sr.WriteLine("depth : {0}, center : {1}, {2}, radius : {3},", depth, (int)pixelSplit._sphere.center.x, (int)pixelSplit._sphere.center.y, (int)pixelSplit._sphere.radius);

        for (int i = 0; i < 4; ++i)
        {
            if (pixelSplit._child.Count > i)
                WriteTest(ref sr, pixelSplit._child[i], depth + 1);
        }
    }
   
    public void RecursiveSplit()
    {
        if (_sphere.radius <= _maxSplitRadius)
            return;

        // top left.
        if (_child.Count <= 0)
        {
            PixelSplit topLeft = new PixelSplit();
            topLeft._sphere.radius = _sphere.radius / 2;
            topLeft._sphere.center = new Vector3(_sphere.center.x + (-_sphere.radius / 2), _sphere.center.y + (_sphere.radius / 2), 0);
            _child.Add(topLeft);
            topLeft.RecursiveSplit();
            
        }

        // top right.
        if (_child.Count <= 1)
        {
            PixelSplit topRight = new PixelSplit();
            topRight._sphere.radius = _sphere.radius / 2;
            topRight._sphere.center = new Vector3(_sphere.center.x + (_sphere.radius / 2), _sphere.center.y + (_sphere.radius / 2), 0);
            _child.Add(topRight);
            topRight.RecursiveSplit();
        }
        
        // bottom left.
        if (_child.Count <= 2)
        {
            PixelSplit bottomLeft = new PixelSplit();
            bottomLeft._sphere.radius = _sphere.radius / 2;
            bottomLeft._sphere.center = new Vector3(_sphere.center.x + (-_sphere.radius / 2), _sphere.center.y + (-_sphere.radius / 2), 0);
            _child.Add(bottomLeft);
            bottomLeft.RecursiveSplit();
        }

        // bottom right.
        if (_child.Count <= 3)
        {
            PixelSplit bottomRight = new PixelSplit();
            bottomRight._sphere.radius = _sphere.radius / 2;
            bottomRight._sphere.center = new Vector3(_sphere.center.x + (_sphere.radius / 2), _sphere.center.y + (-_sphere.radius / 2), 0);
            _child.Add(bottomRight);
            bottomRight.RecursiveSplit();
            
        }
    }

    List<Sphere> FindAdjacentSect(Vector3 center, float radius)
    {
        lstAdjacentSect.Clear();
        
        for (int i = 0; i < 4; ++i)
            RecursiveContain(center, radius, _child[i]);


        //Debug.Log("split Count : " + lstAdjacentSect.Count.ToString());

        return lstAdjacentSect;        
    }

    void RecursiveContain(Vector3 center, float radius, PixelSplit pixelSplit)
    {
        if (pixelSplit._child.Count <= 0)
        {
            Rect test = new Rect(pixelSplit._sphere.center.x, pixelSplit._sphere.center.y, pixelSplit._sphere.radius *2, pixelSplit._sphere.radius *2);

            //if (Vector3.Distance(center, pixelSplit._sphere.center) <= radius + pixelSplit._sphere.radius)
            if (GameUtils.InterSectCirCleRect(center, radius, test))
            {
                Sphere Sphere = new Sphere();
                Sphere.center = pixelSplit._sphere.center;
                Sphere.radius = pixelSplit._sphere.radius;

                lstAdjacentSect.Add(Sphere);
            }
            return;
        }
                
        for (int i = 0; i < 4; ++i)
        {
            if (pixelSplit._child.Count > i)
                RecursiveContain(center, radius, pixelSplit._child[i]);
        }
        
    }

    public CollState GetPixelHeight(Vector2 pos, float radius, ref int pixelHeight, ref Color[] alphaColorArray)
    {
        Vector2 pixel = GameUtils.PositionToPixel(pos, _imgWidth, _imgHeight);

        int add = -1;

        bool bEmpty = true;

        if (alphaColorArray[(int)pixel.x + ((int)pixel.y + 1) * (int)_imgWidth].a > 0)
            add = 1;

        for (int idx = 0; idx < radius/3; ++idx)
        {
            int curIdx = (int)pixel.x + ((int)pixel.y + (idx * add)) * (int)_imgWidth;
            int topIdx = (int)pixel.x + ((int)pixel.y + (idx * add) + 1) * (int)_imgWidth;

            if (curIdx < 0 || _imgWidth * _imgHeight <= curIdx ||
                topIdx < 0 || _imgWidth * _imgHeight <= topIdx
                )
            {
                idx += add;
                continue;
            }

            if (alphaColorArray[curIdx].a >= 1.0)
                bEmpty = false;

            if (alphaColorArray[topIdx].a < 1.0 && alphaColorArray[curIdx].a >= 1.0)
            {
                pixelHeight = (int)pixel.y + (idx * add);
                return CollState.success;
            }
        }

        if (bEmpty==false)
            return CollState.blocked;

        return CollState.fail;
    }


    public bool CollisionPixel( Vector2 center, float radius, ref Vector2 getPixel, ref Color[] alphaColorArray )
    {
        FindAdjacentSect(center, radius);

        float pixelDist = 0.0f;
        float prevPixelDist = 1000.0f;
        Vector2 curPixel = Vector2.zero;

        for (int i = 0; i < lstAdjacentSect.Count; ++i)
        {            
            Sphere Sphere = lstAdjacentSect[ i ];
            int x = (int)(((_imgWidth/2) + Sphere.center.x) - Sphere.radius);
            int y = (int)(((_imgHeight/2) + Sphere.center.y) + Sphere.radius);
            int count = (int)Sphere.radius * 2;

            for (int j = 0; j < count; ++j)
            {
                for (int k = 0; k < count; ++k)
                {
                    int realPixelIdx = (x + k) + ((y - j) * (int)_imgWidth);

                    if (realPixelIdx < 0 || _imgWidth * _imgHeight <= realPixelIdx)
                        continue;
                    Color color = alphaColorArray[realPixelIdx];

                    if (color.a >= 1)
                    {
                        curPixel.x = (x + k) - (_imgWidth/2);
                        curPixel.y = -((_imgHeight - (y - j)) - (_imgHeight / 2));

                        pixelDist = Vector2.Distance(center, curPixel);

                        if (prevPixelDist > pixelDist && pixelDist <= radius)
                        {
                            prevPixelDist = pixelDist;
                            getPixel.x = x + k;
                            getPixel.y = y - j;                            
                        }
                    }
                } // end k.
            } // end j.
        } // end i.

        if (prevPixelDist > 0 && prevPixelDist != 1000)
            return true;

        return false;
    }
    
}
